# !/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@作者 杨阳
@时间 2018-07-24
@说明 自动生成Vue页面工具类
@注意事项
"""
import os

from util.generation.generationutil import GenerationConstant
from util.generation.generationutil import GenerationMySqlUtil
from util.generation.generationutil.GenerationConstant import 不生成在查询中的列, 所有时间类型, 不生成在修改中的列
from util.generation.generationutil.GenerationWriteFileUtil import tab, w, delete_files


def create_vue_file(table_sort_name, vue_type):
    """
    创建vue_list文件
    :param table_sort_name:     表名的简写,通常是去掉t_
    :param vue_type:            list或edit
    :return:
    """
    vue_list_file = GenerationConstant.vue_file_path + "{}/{}_{}.vue".format(table_sort_name, table_sort_name, vue_type)
    print("创建vue文件:{}".format(vue_list_file))
    fp = open(vue_list_file, 'w')
    return fp


def write_submit_clear_return_btn(fp):
    """
    生成提交、返回、清空按钮
    :param fp:  操作文件对象
    :return:
    """
    w(fp, tab() + tab() + "<FormItem>")
    w(fp, tab() + tab() + tab() + "<Button type=\"primary\" @click=\"handleSubmit\">提交</Button>")
    w(fp,
      tab() + tab() + tab() + "<Button type=\"primary\" @click=\"handleReturn\" style=\"margin-left: 8px\">返回</Button>")
    w(fp,
      tab() + tab() + tab() + "<Button type=\"primary\" @click=\"handleReset\" style=\"margin-left: 8px\">清空</Button>")
    w(fp, tab() + tab() + "</FormItem>")


def write_form_inputs(fp, columns, table_sort_name):
    """
    生成表单中所有的input
    :param fp:                  操作文件对象
    :param columns:             表格中所有的列
    :param table_sort_name:     表名简写，通常是去掉t_
    :return:
    """
    for column in columns:
        column_comment = column["COLUMN_COMMENT"]
        column_name = column["COLUMN_NAME"]
        data_type = column["DATA_TYPE"]

        if column_name not in 不生成在修改中的列 and column_name != "id":
            w(fp, tab() + tab() + "<FormItem label=\"{}\" prop=\"{}\" style=\"margin-top: 20px;\">"
              .format(column_comment, column_name))
            if data_type in 所有时间类型 and column_name != 'create_time':  # 如果是时间类型，但是不是创建时间
                w(fp, tab() + tab() + tab() +
                  "<DatePicker type=\"date\" placeholder=\"请输入{}...\" style=\"width: 300px\" clearable size=\"large\" @on-change=\"handle_{}\" editable></DatePicker>"
                  .format(column_comment, column_name))
            else:
                w(fp, tab() + tab() + tab() + "<Input v-model=\"formItem.{}\" placeholder=\"请输入{}...\"></Input>"
                  .format(column_name, column_comment))
            w(fp, tab() + tab() + "</FormItem>")


def write_formItem(fp, columns, table_sort_name):
    """
    生成default data中的formItem
    :param fp:                  操作文件对象
    :param columns:             表中所有的列
    :param table_sort_name:     表的简写，通常是去掉t_
    :return:
    """
    w(fp, tab() + tab() + tab() + "formItem: {")  # formItem start
    for column in columns:  # formItem 下的表单的所有文件框
        column_name = column["COLUMN_NAME"]
        if column_name not in 不生成在修改中的列 and column_name != "id":
            w(fp, tab() + tab() + tab() + tab() + "{}: \"\",".format(column_name))
    w(fp, tab() + tab() + tab() + "},")  # forItem end


def write_ruleInline(fp, columns):
    """
    生成表单验证方式
    :param fp:                  文件操作对象
    :param columns:             表中的列
    :param table_sort_name:     表的简写
    :return:
    """
    w(fp, tab() + tab() + tab() + "ruleInline: {")  # ruleInline start
    for column in columns:  # formItem 下的表单的所有文件框
        column_name = column["COLUMN_NAME"]
        # 是否可以为空 NO YES
        column_nullable = column["IS_NULLABLE"]
        # 列的长度
        column_length = column["CHARACTER_MAXIMUM_LENGTH"]
        # 列的类型
        data_type = column["DATA_TYPE"]
        if column_name not in 不生成在查询中的列 and column_name not in 不生成在修改中的列:
            w(fp, tab() + tab() + tab() + tab() + "{}:[".format(column_name))
            if column_nullable == 'NO':  # 表示不允许为空
                w(fp, tab() + tab() + tab() + tab() + tab() + "{required: true, message: '此项为必添项!', trigger: 'blur'},")
            if data_type == 'int' or data_type == 'bigint' or data_type == 'float' or data_type == 'double':
                w(fp, tab() + tab() + tab() + tab() + tab() +
                  "{pattern: \"^[1-9]+\d*$\", message: '必须是数字!', trigger: 'blur'},")
            if data_type not in 所有时间类型:  # 时间类型不需要验证长度
                w(fp, tab() + tab() + tab() + tab() + tab() + "{max: %s, message: '长度不可以超过%s!', trigger: 'blur'}" % (
                    column_length, column_length))

            w(fp, tab() + tab() + tab() + tab() + "],")
    w(fp, tab() + tab() + tab() + "}")  # ruleInline end


def write_created_function(fp, columns, table_sort_name):
    """
    生成created方法
    :param fp:                  文件操作对象
    :param columns:             表中的列
    :param table_sort_name:     表的简写
    :return:
    """
    w(fp, tab() + "created: function () {")  # created start
    w(fp, tab() + tab() + "const id = this.params.id;")
    w(fp, tab() + tab() + "if (\"\" != id) {//这个说明是修改，要发请求获得更有的数据")
    w(fp, tab() + tab() + tab() + "this.$http.get(this.apiUrl() + '%s/get/' + id, {}, {" % (table_sort_name))
    w(fp, tab() + tab() + tab() + tab() + "emulateJSON: true")
    w(fp, tab() + tab() + tab() + "}).then((response) => {")
    w(fp, tab() + tab() + tab() + tab() + "if (response && response.body.success) {")
    for column in columns:
        column_name = column["COLUMN_NAME"]
        if column_name not in 不生成在修改中的列 and column_name != "id":
            w(fp, tab() + tab() + tab() + tab() + tab() + "this.formItem.{} = response.body.{}.{};"
              .format(column_name, table_sort_name, column_name))
    w(fp, tab() + tab() + tab() + tab() + "} else {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "if (response.body.msg === 'session-timeout') {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "window.location.href = \"/\";")
    w(fp, tab() + tab() + tab() + tab() + tab() + "} else {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() +
      "this.$Notice.error({title: \"错误\", desc: response.body.msg});")
    w(fp, tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + "this.$Spin.hide();")
    w(fp, tab() + tab() + tab() + "});")
    w(fp, tab() + tab() + "} else {")
    w(fp, tab() + tab() + tab() + "this.$Spin.hide();")
    w(fp, tab() + tab() + "}")
    w(fp, tab() + "},")  # created end


def write_beforeCreate_function(fp):
    """
    生成beforeCreate方法
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + "beforeCreate: function(){")
    w(fp, tab() + tab() + "this.$Spin.show();")
    w(fp, tab() + "},")


def write_methods_handle_date_methods(fp, columns):
    """
    杳看表格中的列是否有时间类型，如果有生成时间插件方法
    :param fp:          文件操作对象
    :param columns:     表中的列
    :return:
    """
    for i, column in enumerate(columns):
        column_name = column["COLUMN_NAME"]
        data_type = column["DATA_TYPE"]
        if data_type in 所有时间类型 and column_name != "create_time":
            w(fp, tab() + tab() + "handle_%s: function(changeValue, date){" % (column_name))
            w(fp, tab() + tab() + tab() + "this.{} = changeValue;".format(column_name))
            w(fp, tab() + tab() + "},")


def write_methods(fp, columns, table_sort_name):
    """
    生成methods
    :param fp:              文件操作对象
    :param table_name:      表名
    :param table_sort_name: 表名的简写
    :return:
    """
    w(fp, tab() + "methods: {")

    # 查看表格属性中是否包含时间属性，如果包含要生成日期揷件选中方法
    write_methods_handle_date_methods(fp, columns)

    # 生成表表单提交主法
    write_methods_handleSubmit(fp, columns, table_sort_name)

    # 生成返回列表的方法
    write_methods_handleReturn(fp, table_sort_name)

    # 生成清空表单的方法
    write_methods_handleReset(fp, table_sort_name)

    w(fp, tab() + "},")

    w(fp, tab() + "props: ['params']")


def write_methods_handleSubmit(fp, columns, table_sort_name):
    """
    生成methods下的handleSubmit方法
    :param fp:              文件操作对象
    :param table_name:      表名
    :param table_sort_name: 表名的简写
    :return:
    """
    w(fp, tab() + tab() + "handleSubmit: function() {")
    w(fp, tab() + tab() + tab() + "this.$refs['%s_form'].validate((valid) => {" % (table_sort_name))

    w(fp, tab() + tab() + tab() + tab() + "if (valid) {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "this.$http.post(this.apiUrl() + '%s/save/', {" % (table_sort_name))

    for column in columns:
        column_name = column["COLUMN_NAME"]
        if column_name not in 不生成在修改中的列:
            if column_name == "id":
                w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "id: this.params.id,")
            else:
                w(fp, tab() + tab() + tab() + tab() + tab() + tab() +
                  "{}: this.formItem.{},".format(column_name, column_name))
    # group_id
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "group_id: this.params.group_id")

    w(fp, tab() + tab() + tab() + tab() + tab() + "}, {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "emulateJSON: true")
    w(fp, tab() + tab() + tab() + tab() + tab() + "}).then((response) => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "if (response.body.success) {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "this.$Message.success(response.body.msg);")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() +
      "this.$emit('childClickMenu', '这里自己写', '这里自己写', '{}_list');"
      .format(table_sort_name))
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "} else {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() +
      "this.$Notice.error({title: '错误', desc: response.body.msg});")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + "});")
    w(fp, tab() + tab() + tab() + tab() + "} else {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "this.$Notice.error({title: '错误', desc: '请输入完事信息后进行提交!'});")
    w(fp, tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + "})")
    w(fp, tab() + tab() + "},")


def write_edit_vue_file(fp, table_name, table_sort_name):
    """
    向edit_vue文件中写入内容
    :param fp:              文件操作对象
    :param table_name:      表名
    :param table_sort_name: 表名的简写
    :return:
    """

    w(fp, "<template>")  # template start
    w(fp, tab() + "<Form :model=\"formItem\" :rules=\"ruleInline\" :label-width=\"80\" ref=\"{}_form\">"
      .format(table_sort_name))  # form start

    w(fp, tab() + tab() + "<Alert show-icon>")
    w(fp, tab() + tab() + tab() + "基本信息")
    w(fp, tab() + tab() + tab() + "<Icon type=\"ios-lightbulb-outline\" slot=\"icon\"></Icon>")
    w(fp, tab() + tab() + "</Alert>")

    # 表单中的所有属性
    columns = GenerationMySqlUtil.get_table_columns(table_name)
    write_form_inputs(fp, columns, table_sort_name)

    # 提交、返回、清空按钮
    write_submit_clear_return_btn(fp)

    w(fp, tab() + "</Form>")  # form end
    w(fp, "</template>")  # template end

    w(fp, "<script>")  # script start

    w(fp, "export default {")  # export default start
    w(fp, tab() + "data() {")  # data start
    w(fp, tab() + tab() + "return {")
    # 生成data中的formItem
    write_formItem(fp, columns, table_sort_name)
    # 生成表单验证方式
    write_ruleInline(fp, columns)

    w(fp, tab() + tab() + "}")
    w(fp, tab() + "},")  # data end

    # 生成beforeCreated方法
    write_beforeCreate_function(fp)

    # 生成created方法
    write_created_function(fp, columns, table_sort_name)

    # 生成methods
    write_methods(fp, columns, table_sort_name)

    w(fp, "}")  # export default end

    w(fp, "</script>")  # script end

    # 写入样式
    write_style(fp)


def write_methods_handleReturn(fp, table_sort_name):
    """
    生成返回列表页
    :param fp:                  文件操作对象
    :param table_sort_name:     表的简写
    :return:
    """
    w(fp, tab() + tab() + "handleReturn: function() {")
    w(fp, tab() + tab() + tab() + "this.$emit('childClickMenu', '自己写', '自己写', '{}_list');".format(table_sort_name))
    w(fp, tab() + tab() + "},")


def write_methods_handleReset(fp, table_sort_name):
    """
    生清空表单的方法
    :param fp:                  文件操作对象
    :param table_sort_name:     表的简写
    :return:
    """
    w(fp, tab() + tab() + "handleReset: function() {")
    w(fp, tab() + tab() + tab() + "this.$refs['{}_form'].resetFields();".format(table_sort_name))
    w(fp, tab() + tab() + "}")


def write_style(fp):
    w(fp, "<style scoped>")
    write_page_total_style(fp)
    w(fp, "</style>")


def write_page_total_style(fp):
    """
    生成表格翻页工具条的样式
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + "page_tools {")
    w(fp, tab() + tab() + "float: right;")
    w(fp, tab() + tab() + "padding-top: 10px;")
    w(fp, tab() + tab() + "padding-bottom: 10px;")
    w(fp, tab() + "}")


def write_list_view_grouptree(fp):
    """
    生成list页面左侧的机构树
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + tab() + "<Col span=\"6\" order=\"1\">")
    w(fp,
      tab() + tab() + tab() + "<group_tree :tree_data=\"tree_data\" @onLoadTreeData=\"loadTreeData\" @onNodeClick=\"nodeClick\" :isMultiple=\"false\"></group_tree>")
    w(fp, tab() + tab() + "</Col>")


def write_table(fp, table_sort_name):
    """
    生成表格和表格分页
    :param fp:                  文件操作对象
    :param table_sort_name:     表名简写
    :return:
    """
    # 表格
    w(fp, tab() + tab() + tab() +
      "<{}_table :column_header=\"column_header\" :table_data=\"table_data\" :total_page=\"total_page\"></{}_table>"
      .format(table_sort_name, table_sort_name))
    # 表格分页工具栏
    w(fp, tab() + tab() + tab() +
      "<Page :total=\"total_page\" class=\"page_tools\" @on-change=\"change\" @on-page-size-change=\"change\"></Page>")


def write_search(fp, columns):
    """
    生成表格查询条件
    :param fp:              文件操作对象
    :param columns:         表格中的列
    :return:
    """
    for column in columns:
        column_name = column["COLUMN_NAME"]
        column_comment = column["COLUMN_COMMENT"]
        data_type = column["DATA_TYPE"]
        if column_name not in 不生成在查询中的列:
            if data_type == "datetime" or data_type == "date":  # 如果是时间类型
                w(fp, tab() + tab() + tab() + tab() + "<FormItem>")
                w(fp, tab() + tab() + tab() + tab() + tab() +
                  "<DatePicker type=\"date\" placeholder=\"{}-起始...\" style=\"width: 300px\" clearable size=\"large\" @on-change=\"handle_search_start_{}\" editable></DatePicker>"
                  .format(column_comment, column_name))
                w(fp, tab() + tab() + tab() + tab() + "</FormItem>")
                w(fp,
                  tab() + tab() + tab() + tab() + "<FormItem><Icon type=\"minus-round\"></Icon><Icon type=\"minus-round\"></Icon></FormItem>")

                w(fp, tab() + tab() + tab() + tab() + "<FormItem>")
                w(fp, tab() + tab() + tab() + tab() + tab() +
                  "<DatePicker type=\"date\" placeholder=\"{}-结束...\" style=\"width: 300px\" clearable size=\"large\" @on-change=\"handle_search_end_{}\" editable></DatePicker>"
                  .format(column_comment, column_name))
                w(fp, tab() + tab() + tab() + tab() + "</FormItem>")

            elif column_name == 'sex' or column_name == 'status' or column_name == 'pubish_status':
                w(fp, tab() + tab() + tab() + tab() + "<FormItem>")
                w(fp,
                  tab() + tab() + tab() + tab() + tab() + "<Select style=\"width:300px\" size=\"large\" clearable v-model=\"search_{}\">".format(
                      column_name))
                w(fp, tab() + tab() + tab() + tab() + tab() + tab() +
                  "<Option v-for=\"(item, index) in search_%s\" :value=\"item.value\" :key=\"index\">{{ item.label }}</Option>" % (
                      column_name))
                w(fp, tab() + tab() + tab() + tab() + tab() + "</Select>".format(column_name))
                w(fp, tab() + tab() + tab() + tab() + "</FormItem>")
            else:
                w(fp, tab() + tab() + tab() + tab() + "<FormItem>")
                w(fp,
                  tab() + tab() + tab() + tab() + tab() + "<Input type=\"text\" placeholder=\"请输入{}\" size=\"large\" style=\"width: 300px\" clearable v-model=\"search_{}\"></Input>"
                  .format(column_comment, column_name))
                w(fp, tab() + tab() + tab() + tab() + "</FormItem>")

    w(fp, tab() + tab() + tab() + tab() + "<FormItem>")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + "<Button type=\"primary\" @click=\"loadTableData\" size=\"large\">查询</Button>")
    w(fp, tab() + tab() + tab() + tab() + "</FormItem>")
    w(fp, tab() + tab() + tab() + "</Form>")


def write_list_view(fp, columns, table_sort_name):
    """
    生成list页面右側的数据表格
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + tab() + "<Col span=\"18\" order=\"2\">")
    w(fp,
      tab() + tab() + tab() + "<Form ref=\"%sformInline\" inline :style=\"{'padding-top': '20px'}\">" % table_sort_name)

    # 生成查询表单
    write_search(fp, columns)

    # 生成增加按钮
    w(fp, tab() + tab() + tab() +
      "<Button type=\"info\" icon=\"android-add-circle\" shape=\"circle\" @click=\"add_{}\" :disabled=\"btn_disabled\">增加</Button>"
      .format(table_sort_name))

    write_table(fp, table_sort_name)

    w(fp, tab() + tab() + "</Col>")


def write_table_column_header_status_render(fp):
    """
    生成表格列头中status字段显示的render
    :param fp:              文件操作对象
    :return:
    """
    w(fp, tab() + tab() + tab() + tab() + tab() + "{title: '%s',key: '%s', align: 'center'," % (
        "状态", "status"))
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "render: (h, params) => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "var icon = 'heart-broken';")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "var color = 'red';")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "if (params.row.status == 1) {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "icon = 'heart';")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "color = 'green';")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")

    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "return h('div', [")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "h('Icon', {")

    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "props: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "type: icon,")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "size: '25',")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "color: color")

    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "})")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "]);")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + "},")


def write_table_column_header_handler_render(fp, table_sort_name):
    """
    生成表格中操作的列
    :param fp:      文件操作对象
    :return:
    """
    w(fp,
      tab() + tab() + tab() + tab() + tab() + "{title: '操作',key: 'handler',align: 'center',render: (h, params) => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "const _this = this;")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "return h('div', [")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "h('Icon', {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "props: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "type: 'edit',")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "size: '20'")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "},")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "style: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "marginRight: '5px',")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "cursor: 'pointer'")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "},")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "on: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "click: () => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() +
      "this.$emit('childClickMenu', '自己写', '自己写', '%s_edit', {\"id\": params.row.id});" % (table_sort_name))
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}, 'View'),")

    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "h('Icon', {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "props: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "type: 'trash-a',")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "size: '20'")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "},")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "style: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "cursor: 'pointer'")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "},")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "on: {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "click: () => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "if (params.row.id == -1) {")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "this.$Notice.error({title: '警告', desc: '基础数据不可以删除!'});")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "return;")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "this.$Modal.warning({")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "title: \"注意\",")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "content:\"确定要删除数据吗？\",")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "onOk: function () {")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "this.$http.delete(this.apiUrl() + '%s/delete/' + params.row.id, {" % (
          table_sort_name))
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "emulateJSON: true")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}).then((response) => {")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "if (response.body.success) {")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "this.$Message.success(response.body.msg);")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "_this.loadTableData();")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "} else {")
    w(fp,
      tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "this.$Notice.error({title: '错误', desc: response.body.msg});")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "});")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "});")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + tab() + "}, 'Delete')")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "]);")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + "],")


def write_table_search_sex_select_data(fp, column_name):
    """
    主要和于生成查询表单中sex下拉选择的列
    :param fp:              文件操作对象
    :param column_name:     列名
    :return:
    """
    w(fp, tab() + tab() + tab() + tab() + "search_%s: [{" % (column_name))
    w(fp, tab() + tab() + tab() + tab() + tab() + "value: \"-1\",")
    w(fp, tab() + tab() + tab() + tab() + tab() + "label: \"请选择性别\"")
    w(fp, tab() + tab() + tab() + tab() + "}, {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "value: \"男\",")
    w(fp, tab() + tab() + tab() + tab() + tab() + "label: \"男\"")
    w(fp, tab() + tab() + tab() + tab() + "}, {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "value: \"女\",")
    w(fp, tab() + tab() + tab() + tab() + tab() + "label: \"女\"")
    w(fp, tab() + tab() + tab() + tab() + "}],")


def write_table_search_status_select_data(fp, column_name):
    """
    主要和于生成查询表单中statux下拉选择的列
    :param fp:              文件操作对象
    :param column_name:     列名
    :return:
    """
    w(fp, tab() + tab() + tab() + tab() + "search_%s: [{" % (column_name))
    w(fp, tab() + tab() + tab() + tab() + tab() + "value: \"0\",")
    w(fp, tab() + tab() + tab() + tab() + tab() + "label: \"未发布\"")
    w(fp, tab() + tab() + tab() + tab() + "}, {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "value: \"1\",")
    w(fp, tab() + tab() + tab() + tab() + tab() + "label: \"已发布\"")
    w(fp, tab() + tab() + tab() + tab() + "}],")


def write_default_data(fp, columns, table_sort_name):
    """
    生成defualt 下的 data对象
    :param fp:                  文件操作对象
    :param columns:             表格中的列
    :param table_sort_name:     表名的简写
    :return:
    """
    w(fp, tab() + tab() + "data() {")
    w(fp, tab() + tab() + tab() + "return {")

    # 表的列头
    w(fp, tab() + tab() + tab() + tab() + "column_header:[")

    w(fp, tab() + tab() + tab() + tab() + tab() + "{type: 'selection',width: 60,align: 'center'},")
    for i, column in enumerate(columns):
        column_name = column["COLUMN_NAME"]
        column_comment = column["COLUMN_COMMENT"]
        if 'status' in column_name:
            # 生成status列的render
            write_table_column_header_status_render(fp)
        else:
            if column_name not in 不生成在查询中的列:
                w(fp, tab() + tab() + tab() + tab() + tab() + "{title: '%s', key: '%s', align: 'left'}," % (
                    column_comment, column_name))

    # 生成表格操作render
    write_table_column_header_handler_render(fp, table_sort_name)

    w(fp, tab() + tab() + tab() + tab() + "table_data: [],")
    w(fp, tab() + tab() + tab() + tab() + "total_page: 0,")
    w(fp, tab() + tab() + tab() + tab() + "current_page: 1,")
    w(fp, tab() + tab() + tab() + tab() + "tree_data: [],")
    w(fp, tab() + tab() + tab() + tab() + "current_group_id: '',")

    for i, column in enumerate(columns):
        column_name = column["COLUMN_NAME"]
        data_type = column["DATA_TYPE"]
        if column_name not in 不生成在查询中的列:
            if column_name == 'sex':
                write_table_search_sex_select_data(fp, column_name)
            elif column_name == 'status' or column_name == 'pubish_status':
                write_table_search_status_select_data(fp, column_name)
            elif data_type == 'datetime' or data_type == 'time' or data_type == 'date':
                # 如果是时间类型要生成两对
                w(fp, tab() + tab() + tab() + tab() + "search_start_{}: '',".format(column_name))
                w(fp, tab() + tab() + tab() + tab() + "search_end_{}: '',".format(column_name))
            else:
                w(fp, tab() + tab() + tab() + tab() + "search_{}: '',".format(column_name))

    w(fp, tab() + tab() + tab() + tab() + "btn_disabled: true")
    w(fp, tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + "},")


def write_default_components(fp, table_sort_name):
    """
    生成default下面的组件对象，主要和于注册组件
    :param fp:                  文件操作对象
    :param table_sort_name:     表格名称简写
    :return:
    """
    w(fp, tab() + tab() + "//注册组件")
    w(fp, tab() + tab() + "components: {")
    w(fp, tab() + tab() + tab() + "group_tree: group_tree,")
    w(fp, tab() + tab() + tab() + "{}_table: {}_table".format(table_sort_name, table_sort_name))
    w(fp, tab() + tab() + "},")


def write_default_created(fp):
    """
    生成default下的created方法，这个方法是页面加载完成后调用
    :param fp:     文件操作对象
    :return:
    """
    w(fp, tab() + tab() + "created: function () {")
    w(fp, tab() + tab() + tab() + "//加载表格数据")
    w(fp, tab() + tab() + tab() + "this.loadTableData();")
    w(fp, tab() + tab() + tab() + "//加载机构树数据")
    w(fp, tab() + tab() + tab() + "this.loadTreeData();")
    w(fp, tab() + tab() + "},")


def write_default_methods_datetype_input(fp, columns):
    """
    查看表中是否包含日期类型，如果包含那么生成日期揷件的方法
    :param fp:          文件操作对象
    :param columns:     表格所有列
    :return:
    """
    for i, column in enumerate(columns):
        column_name = column["COLUMN_NAME"]
        if "date" in column_name or "time" in column_name:
            w(fp, tab() + tab() + tab() + "handle_search_start_%s: function(changeValue, date) {" % (column_name))
            w(fp, tab() + tab() + tab() + tab() + "this.search_start_%s = changeValue;" % (column_name))
            w(fp, tab() + tab() + tab() + "},")

            w(fp, tab() + tab() + tab() + "handle_search_end_%s: function(changeValue, date) {" % (column_name))
            w(fp, tab() + tab() + tab() + tab() + "this.search_end_%s = changeValue;" % (column_name))
            w(fp, tab() + tab() + tab() + "},")


def write_default_methods_change(fp):
    """
    生成表格翻页方法
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + tab() + tab() + "/**")
    w(fp, tab() + tab() + tab() + " * 点击分页，页数标签时调用的方法")
    w(fp, tab() + tab() + tab() + " * @param page_num  页码改变的回调，返回改变后的页码")
    w(fp, tab() + tab() + tab() + " */")
    w(fp, tab() + tab() + tab() + "change: function (page_num) {")
    w(fp, tab() + tab() + tab() + tab() + "this.current_page = page_num;")
    w(fp, tab() + tab() + tab() + tab() + "this.loadTableData();")
    w(fp, tab() + tab() + tab() + "},")


def write_default_methods_loadTableData(fp, columns, table_sort_name):
    """
    生成 default 下的 methods 下的 加载表格数据的方法
    :param fp:                  文件操作对象
    :param columns:             表格中所有列
    :param table_sort_name:     表名的简写
    :return:
    """
    w(fp, tab() + tab() + tab() + "loadTableData: function () {")
    w(fp, tab() + tab() + tab() + tab() + "this.$http.post(this.apiUrl() + \"%s/grid/\", {" % (table_sort_name))

    w(fp, tab() + tab() + tab() + tab() + tab() + "group_id: this.current_group_id,")

    for i, column in enumerate(columns):
        column_name = column["COLUMN_NAME"]
        data_type = column["DATA_TYPE"]
        if column_name not in 不生成在查询中的列:
            if data_type == "datetime" or data_type == "time" or data_type == "date":
                w(fp, tab() + tab() + tab() + tab() + tab() + "search_start_{}: this.search_start_{},"
                  .format(column_name, column_name))
                w(fp, tab() + tab() + tab() + tab() + tab() + "search_end_{}: this.search_end_{},"
                  .format(column_name, column_name))
            else:
                w(fp, tab() + tab() + tab() + tab() + tab() +
                  "search_{}: this.search_{},".format(column_name, column_name))

    w(fp, tab() + tab() + tab() + tab() + tab() + "current_page: this.current_page")

    w(fp, tab() + tab() + tab() + tab() + "}, {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "emulateJSON: true")
    w(fp, tab() + tab() + tab() + tab() + "}).then((response) => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "if (response.body.success) {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "this.table_data = response.body.grid;")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "this.total_page = response.body.total_count;")
    w(fp, tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + "});")
    w(fp, tab() + tab() + tab() + "},")


def write_default_methods_loadTreeData(fp):
    """
    生成加载机构树方法
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + tab() + tab() + "loadTreeData: function (item, callback) {")
    w(fp, tab() + tab() + tab() + tab() + "var parentid = '-1';")
    w(fp, tab() + tab() + tab() + tab() + "if (item != undefined) {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "parentid = item.id;")
    w(fp, tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + "this.$http.post(this.apiUrl() + \"group/tree/\", {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "parent_id: parentid")
    w(fp, tab() + tab() + tab() + tab() + "}, {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "emulateJSON: true")
    w(fp, tab() + tab() + tab() + tab() + "}).then((response) => {")
    w(fp, tab() + tab() + tab() + tab() + tab() + "if (item != undefined) {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "callback(response.body);")
    w(fp, tab() + tab() + tab() + tab() + tab() + "} else {")
    w(fp, tab() + tab() + tab() + tab() + tab() + tab() + "this.tree_data = response.body;")
    w(fp, tab() + tab() + tab() + tab() + tab() + "}")
    w(fp, tab() + tab() + tab() + tab() + "});")
    w(fp, tab() + tab() + tab() + "},")


def write_tree_click_node(fp):
    """
    生成点击树节点的方法
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + tab() + tab() + "nodeClick: function (node) {")
    w(fp, tab() + tab() + tab() + tab() + "var groupid = node.id;")
    w(fp, tab() + tab() + tab() + tab() + "this.current_group_id = groupid;")
    w(fp, tab() + tab() + tab() + tab() + "this.loadTableData();")
    w(fp, tab() + tab() + tab() + tab() + "this.btn_disabled = false;")
    w(fp, tab() + tab() + tab() + "},")


def write_default_methods_add_entity(fp, tablea_sort_name):
    """
    生成增加实体的方法
    :param fp:                  文件操作对象
    :param tablea_sort_name:    表的简称
    :return:
    """
    w(fp, tab() + tab() + tab() + "add_%s: function () {" % (tablea_sort_name))
    w(fp, tab() + tab() + tab() + tab() +
      "this.$emit('childClickMenu', '自己写', '自己写', '%s_edit', {\"group_id\": this.current_group_id, \"id\": ''});" % (
          tablea_sort_name))
    w(fp, tab() + tab() + tab() + "}")


def write_default_methods(fp, columns, table_sort_name):
    """
    生成default下的methods对象，放着页面中的方法
    :param fp:      文件操作对象
    :return:
    """
    w(fp, tab() + tab() + "methods:{")

    # 生成时间插件使用的方法
    write_default_methods_datetype_input(fp, columns)

    # 生成表表格翻页方法
    write_default_methods_change(fp)

    # 生成表格加载数据方法
    write_default_methods_loadTableData(fp, columns, table_sort_name)

    # 生成异步加载树的方法
    write_default_methods_loadTreeData(fp)

    # 生成点击树节点的方法
    write_tree_click_node(fp)

    write_default_methods_add_entity(fp, table_sort_name)

    w(fp, tab() + tab() + "}")


def write_list_script(fp, columns, table_sort_name):
    """
    生成script标签内容
    :param fp:                  文件操作对象
    :param columns:             表格所有列
    :param table_sort_name:     表格名称简写
    :return:
    """
    w(fp, "<script>")
    # 引入组件
    w(fp, tab() + "import group_tree from '../utils/tree_components_util'")
    w(fp, tab() + "import {}_table from '../utils/table_components_util'".format(table_sort_name))

    # 生成default data
    w(fp, tab() + "export default {")

    # 生成default 下的 data对象
    write_default_data(fp, columns, table_sort_name)

    # 生成 default 下的 components
    write_default_components(fp, table_sort_name)

    # 生成 default 下的 created方法
    write_default_created(fp)

    # 生成 default 下的 methods对象
    write_default_methods(fp, columns, table_sort_name)

    w(fp, tab() + "}")

    w(fp, "</script>")


def write_list_vue_file(fp, table_name, table_sort_name):
    """
    生成list vue文件
    :param fp:                  文件对象
    :param table_name:          表格名称
    :param table_sort_name:     表格名称简写
    :return:
    """
    w(fp, "<template>")
    w(fp, tab() + "<Row>")

    ####################左边的机构树####################
    write_list_view_grouptree(fp)

    ####################右边的数据表####################
    columns = GenerationMySqlUtil.get_table_columns(table_name)
    write_list_view(fp, columns, table_sort_name)

    w(fp, tab() + "</Row>")
    w(fp, "</template>")

    # 生成script
    write_list_script(fp, columns, table_sort_name)

    # 生成样式标签
    write_style(fp)


def generation_vue():
    """
    生成vue文件
    :return:
    """
    table_list = GenerationMySqlUtil.get_database_tables()
    for table in table_list:
        table_name = table["table_name"]
        model_name = table["model_name"]
        # 这个表示从第二个开始截取字符串，截到最后
        table_sort_name = table_name[2:]
        print("表名：{}===>实体名：{}===>表名简写：{}".format(table_name, model_name, table_sort_name))

        # 创建文件夹
        os.mkdir(GenerationConstant.vue_file_path + "{}/".format(table_sort_name))

        # 创建文件夹内的文件
        fp = create_vue_file(table_sort_name, "list")
        write_list_vue_file(fp, table_name, table_sort_name)
        fp.close()

        fp = create_vue_file(table_sort_name, "edit")
        write_edit_vue_file(fp, table_name, table_sort_name)
        fp.close()


if __name__ == '__main__':
    delete_files(GenerationConstant.vue_file_path)
    generation_vue()
